package com.cropdoctor.service.impl;

import com.aliyun.oss.OSS;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.cropdoctor.common.CustomException;
import com.cropdoctor.common.Result;
import com.cropdoctor.mapper.SysUserMapper;
import com.cropdoctor.model.dto.PwdFormDto;
import com.cropdoctor.model.po.SysUserPo;
import com.cropdoctor.model.vo.UserVO;
import com.cropdoctor.mybatisplus.BaseServiceImpl;
import com.cropdoctor.service.SysUserService;

import com.cropdoctor.util.AliOssUtil;
import com.cropdoctor.util.ContextGet;
import com.cropdoctor.util.JwtTokenUtils;
import io.netty.util.internal.StringUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.data.redis.connection.BitFieldSubCommands;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.util.DigestUtils;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletRequest;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.List;

/**
 * Description: 【 用户表 Service接口实现类 】
 */
@Service
public class SysUserServiceImpl extends BaseServiceImpl<SysUserMapper, SysUserPo> implements SysUserService {

    @Autowired
    AliOssUtil ossUtil;

    @Autowired
    OSS ossClient;

    private final static String USER_SIGN_KEY = "sign:";
    @Qualifier("redisTemplate")
    @Autowired
    private RedisTemplate redisTemplate;

    @Override
    public SysUserPo selectByName(String userName) {
        return baseMapper.selectByName(userName);
    }

    @Override
    public SysUserPo saveEntity(SysUserPo sysUserPo) {
        save(sysUserPo);
        return sysUserPo;
    }

    @Override
    public SysUserPo getByOpenId(String openid) {
        return getOne(new LambdaQueryWrapper<SysUserPo>().eq(SysUserPo::getOpenid,openid));
    }

    @Override
    public Result<UserVO> getUserInfo(HttpServletRequest request) {
        //获取请求头中的 Authorization:
        String tokenHeader = request.getHeader(JwtTokenUtils.TOKEN_HEADER);
        String token = tokenHeader.replace(JwtTokenUtils.TOKEN_PREFIX, "");//去掉jwt中的Bearer 前缀
        if(JwtTokenUtils.isExpiration(token)) return null;
        String username = JwtTokenUtils.getUsername(token);//获取用户账号

        UserVO userVO = baseMapper.selectWithRoleByName(username);
        return Result.success(userVO);
    }

    @Override
    public Result<String> updateUserName(String userName) {
        LambdaUpdateWrapper<SysUserPo> wrapper = new LambdaUpdateWrapper<>();
        long userId = ContextGet.getUserId();
        wrapper.eq(SysUserPo::getId,userId).set(SysUserPo::getUserName,userName);
        int result = baseMapper.update(null,wrapper);
        return result > 0 ? Result.success("修改成功!") : Result.error("修改失败");
    }

    @Override
    public Result<String> updateAvatar(MultipartFile img) {
        String url = null;
        try {
            //获取原始的文件名
            long userId = ContextGet.getUserId();
            String originalFilename = img.getOriginalFilename();
            String md5 = DigestUtils.md5DigestAsHex(img.getBytes());
            String objectName = md5ToObjectName(originalFilename,md5);
            boolean found = ossClient.doesObjectExist("crop-doctor", "user/"+objectName);
            LambdaUpdateWrapper<SysUserPo> wrapper = new LambdaUpdateWrapper<>();
            if(!found){//如果用户用的是oss中不存在的图片 则需删除旧图片以及上传新图片
                url = ossUtil.upload(img.getBytes(), "user/"+objectName);//图片不存在则上传新图片
                SysUserPo sysUserPo = baseMapper.selectById(userId);
                String oldImg = sysUserPo.getAvatarUrl();
                if(!StringUtil.isNullOrEmpty(oldImg)){ //如果有旧图片则需要删除
                    String delObjectName = UrlToObjectName(oldImg);
                    ossClient.deleteObject("crop-doctor", "user/"+delObjectName);
                }
            }else{
                url = "https://crop-doctor.oss-cn-beijing.aliyuncs.com/user/"+objectName;//oss中已经存在该图片 直接拼接地址
            }
            wrapper.eq(SysUserPo::getId,userId).set(SysUserPo::getAvatarUrl,url);
            int result = baseMapper.update(null, wrapper);
            return result > 0 ? Result.success("修改成功!") : Result.error("修改失败");
        } catch (Exception e) {
            e.printStackTrace();
            throw new CustomException("上传图片失败!");
        }
    }

    @Override
    public Result<String> updatePwd(PwdFormDto pwdFormDto) {
        String newPwd = pwdFormDto.getNewPwd();
        String oldPwd = pwdFormDto.getOldPwd();
        SysUserPo currentUser = baseMapper.selectById(ContextGet.getUserId());
        String encodedPassword = currentUser.getPassword();
        BCryptPasswordEncoder bCryptPasswordEncoder = new BCryptPasswordEncoder();
        boolean matches = bCryptPasswordEncoder.matches(oldPwd, encodedPassword);//将用户输入的原密码和数据库中的比较
        if(!matches){
            return Result.error("原密码不正确!");
        }
        String encode = bCryptPasswordEncoder.encode(newPwd);//编码后存入数据库
        long userId = ContextGet.getUserId();
        LambdaUpdateWrapper<SysUserPo> wrapper = new LambdaUpdateWrapper<>();
        wrapper.eq(SysUserPo::getId,userId).set(SysUserPo::getPassword,encode);
        int result = baseMapper.update(null, wrapper);
        return result > 0 ? Result.success("修改成功!") : Result.error("修改失败");
    }

    @Override
    public Result<String> dailySign() {
        long userId = ContextGet.getUserId();
        LocalDateTime now = LocalDateTime.now();
        String keySuffix = now.format(DateTimeFormatter.ofPattern(":yyyyMM"));
        String key = USER_SIGN_KEY + userId + keySuffix;
        int dayOfMonth = now.getDayOfMonth();
        if(!redisTemplate.opsForValue().getBit(key,dayOfMonth-1)){
            redisTemplate.opsForValue().setBit(key,dayOfMonth - 1,true);
            return Result.success("签到成功");
        }
        return Result.success("今日已签到");
    }

    @Override
    public Result<Integer> getSign() {
        long userId = ContextGet.getUserId();
        LocalDateTime now = LocalDateTime.now();
        String keySuffix = now.format(DateTimeFormatter.ofPattern(":yyyyMM"));
        String key = USER_SIGN_KEY + userId + keySuffix;

        int dayOfMonth = now.getDayOfMonth();
        List<Long> result = redisTemplate.opsForValue().bitField(key,
                BitFieldSubCommands.create().get(BitFieldSubCommands.BitFieldType.unsigned(dayOfMonth)).valueAt(0));
        if(result == null || result.isEmpty()){
            return Result.success(0);
        }
        Long num = result.get(0);
        if(num == null || num == 0){
            return Result.success(0);
        }
        int count = 0;
        while(true){
            if((num & 1) == 0){
                break;
            }else{
                count++;
            }
            num >>>= 1;
        }
        return Result.success(count);
    }

    public String md5ToObjectName(String fileName,String md5){
        return md5.charAt(0) +"/"+md5.charAt(1) + "/" + md5 + fileName.substring(fileName.lastIndexOf("."));
    }

    public String UrlToObjectName(String url){
        String[] split = url.split("/");
        int length = split.length;
        String objectName = "";
        for(int i = 3; i > 0; i--){
            objectName +=  split[length - i] + "/";
        }
        return objectName.substring(0,objectName.length()-1);//不包含最后一个/
    }


}
